package com.googlecode.imanager.client.report;

import com.googlecode.imanager.client.Container;
import com.googlecode.imanager.client.Document;
import com.googlecode.imanager.client.Label;
import com.googlecode.imanager.client.event.EvaluationTime;
import com.googlecode.imanager.client.event.PhaseEvent;
import com.googlecode.imanager.client.util.Utils;
import com.googlecode.imanager.client.value.HasValue;
import com.googlecode.imanager.client.value.HasValueType;
import com.googlecode.imanager.client.value.ValueType;
import com.googlecode.imanager.client.value.format.Formatter;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public class Field<T> extends Label implements HasValue {

    private static final long serialVersionUID = 1L;

    private EvaluationTime evaluationTime;
    private ValueType defaultValueType;
    private Formatter<T> formatter;
    private T value;
    
    public Field() {
        super();
        evaluationTime = EvaluationTime.DEFAULT;
    }

    public Field(Container parent) {
        this();
        setParent(parent);
    }
    
    @Override
    protected void onPhaseEvent(PhaseEvent e){
        super.onPhaseEvent(e);
        if (e.getEventType() == evaluationTime){
            doEvaluate();
        }
    }
    
    public void setValue(T value){
        if (!Utils.isEquals(this.value, value)){
            this.value = value;
            if (evaluationTime == EvaluationTime.NOW){
                doEvaluate();
            }
        }
    }

    private void doEvaluate() {
        String text = null;
        
        if (value != null) {
            ValueType valueType = super.getValueType();
            
            if (valueType == null){
                ValueType type = ValueType.getTypeOf(value.getClass());

                if (type != null){
                    defaultValueType = type;
                    valueType = type;
                }
            }
            
            Formatter<?> fmt = formatter;
            if (fmt == null
                    && valueType != null){
                Document document = getDocument();

                if (document != null){
                    fmt = document.getFormatter(valueType);
                }
            }
            
            if (fmt != null){
                text = fmt.format(value, valueType);
            }
        } else {
            if (formatter != null){
                text = formatter.format(value);
            }
        }

        super.setText(text);
    }

    @Override
    public T getValue() {
        return value;
    }

    public void setFormatter(Formatter<T> formatter) {
        this.formatter = formatter;
    }

    public Formatter<T> getFormatter() {
        return formatter;
    }

    @Override
    public ValueType getValueType() {
        ValueType valueType = super.getValueType();
        
        if (valueType == null){
            valueType = defaultValueType;
            
            if (valueType == null
                    && formatter instanceof HasValueType){
                valueType = ((HasValueType) formatter).getValueType();
            }
        }
        return valueType;
    }

    public EvaluationTime getEvaluationTime() {
        return evaluationTime;
    }

    public void setEvaluationTime(EvaluationTime evaluationTime) {
        if (evaluationTime == null){
            evaluationTime = EvaluationTime.DEFAULT;
        }
        if (this.evaluationTime != evaluationTime){
            this.evaluationTime = evaluationTime;
            if (evaluationTime == EvaluationTime.NOW){
                doEvaluate();
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public Field<T> clone() {
        return (Field<T>) super.clone();
    }
    
}
